/*
 * To change this templa
 * te, choose Tools | Templates
 * and open the template in the editor.
 */
package automatolfa;

import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author IVAN
 */
public class AnalisadorSintatico {

    private List<String> _lstTokens;
    private List<String> _lstErros;
    private ArrayList<String> _LstAnalise;
    //Armazena a posição da cabeça de leitura da fita
    private int index;
    public boolean controle = true;

    public AnalisadorSintatico() {
    }

//    public AnalisadorSintatico(AnalisadorLexico Lexico) {
//        this._lstTokens = Lexico.getLstToken();
//        this._lstErros = new ArrayList<>();
//        this.index = 0;
//    }
    public String ObterTokenAtual() {
        if (index < _lstTokens.size()) {
            return _lstTokens.get(index).trim();
        } else {
            Erro("Fim da lista");
            return "";
        }
    }

    public void Avancar() {
        index++;
    }

    public boolean Consumir(String token) {
        boolean retorno;
        retorno = (_lstTokens.get(index) == token);
        _LstAnalise.add(token);
        Avancar();
        if (!retorno) {
            Erro("Não foi possivel consumir o token:" + token);
        }
        //throw new Exception("Não foi possivel consumir o token:" + token);
        return retorno;
    }

    public void Erro(String menssagem) {
        if (_lstErros == null) {
            _lstErros = new ArrayList<String>();
        }

        _lstErros.add(menssagem);
        getLstAnalise().add(menssagem);
    }

    void Principal() {
        TipoVariavel();
        Consumir("PalavraReservadaMain");
        Consumir("SimboloAbreParenteses");
        Consumir("SimboloFechaParenteses");
        Chaves();

    }

    void Chaves() {
        Consumir("SimboloAbreChaves");
        Codigo();
        Consumir("SimboloFechaChaves");
    }

    private void TipoVariavel() {
        String tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "TipoInt":
                Consumir("TipoInt");
                break;
            case "TipoChar":
                Consumir("TipoChar");
                break;
            case "TipoFloat":
                Consumir("TipoFloat");
                break;
            default:
                Erro("Tipo de variável não existe!");
                break;
        }
    }

    private void Codigo() {
        String tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "TipoInt":
            case "TipoFloat":
            case "TipoChar":
                Declaracao();
                Codigo();
                break;
            case "NomeVariavel":
            case "ValorInt":
            case "ValorFloat":
            case "ValorChar":
                Expressao();
                Codigo();
                break;
            case "PalavraReservadaElse":
            case "PalavraReservadaIf":
                CondicaoIf();
                Codigo();
                break;
            case "PalavraReservadaFor":
                LacoFor();
                Codigo();
                break;
            case "PalavraReservadaWhile":
                LacoWhile();
                Codigo();
                break;
            case "PalavraReservadaDo":
                LacoDo();
                Codigo();
                break;
            case "SimboloPontoVirgula":
                Consumir("SimboloPontoVirgula");
                break;
            case "OperadorRetorno":
                Consumir("OperadorRetorno");
                Codigo();
                break;    
            
            case "SimboloFechaChaves":
                //Consumir("SimboloFechaChaves");
                break;
            /*case "fecha_chaves":
             String tokenAnterior = ObterTokenAnterior();
             if(tokenAnterior != "fecha_chaves" && tokenAnterior != "ponto_virgula")
             Erro("Falta ponto_virgula ou fecha_chaves antes do fecha_chaves atual");
             break;*/
            default:
                Erro("Erro de Codigo!");
                break;
        }

    }

    private void Expressao() {
        String tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "NomeVariavel":
                Consumir("NomeVariavel");
                Sinal();
                break;
            case "ValorInt":
                Consumir("ValorInt");
                Sinal();
                break;
            case "ValorFloat":
                Consumir("ValorFloat");
                Sinal();
                break;
            case "ValorChar":
                Consumir("ValorChar");
                Sinal();
                break;
            case "SimboloAbreParenteses":
                Consumir("SimboloAbreParenteses,");
                Expressao();
                Consumir("SimboloFechaParenteses");
                Sinal();
                break;
            default:
                Erro("Expressao deve iniciar com variavel, inteiro ou caracter!");
                break;
        }
    }

    private void Declaracao() {
        String tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "TipoInt":
                Consumir("TipoInt");
                Consumir("NomeVariavel");
                Sinal();
                break;
            case "TipoFloat":
                Consumir("TipoFloat");
                Consumir("NomeVariavel");
                Sinal();
                break;
            case "TipoChar":
                Consumir("TipoChar");
                Consumir("NomeVariavel");
                Sinal();
                break;
            default:
                Erro("Declaração inválida!");
                break;
        }
    }

    private void Sinal() {
        String tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "OperadorSoma":
                Consumir("OperadorSoma,");
                Expressao();
                break;
            case "OperadorSubtracao":
                Consumir("OperadorSubtracao");
                Expressao();
                break;
            case "OperadorMultiplicacao":
                Consumir("OperadorMultiplicacao");
                Expressao();
                break;
            case "OperadorDivisao":
                Consumir("OperadorDivisao");
                Expressao();
                break;
            case "OperadorModulo":
                Consumir("OperadorModulo");
                Expressao();
                break;
            case "OperadorMaior":
                Consumir("OperadorMaior");
                Expressao();
                break;
            case "OperadorMaiorIgual":
                Consumir("OperadorMaiorIgual");
                Expressao();
                break;
            case "OperadorMenor":
                Consumir("OperadorMenor");
                Expressao();
                break;
            case "OperadorMenorIgual":
                Consumir("OperadorMenorIgual");
                Expressao();
                break;
            case "OperadorIgual":
                Consumir("OperadorIgual");
                Expressao();
                break;
            case "OperadorDiferente":
                Consumir("OperadorDiferente");
                Expressao();
                break;
            case "OperadorOuRelacional":
                Consumir("OperadorOuRelacional");
                Expressao();
                break;
            case "OperadorERelacional":
                Consumir("OperadorERelacional");
                Expressao();
                break;
            case "OperadorAtribuicao":
                Consumir("OperadorAtribuicao");
                Expressao();
                break;
            case "OperadorIncremento":
                Consumir("OperadorIncremento");
                Expressao();
                break;
            case "OperadorDecremento":
                Consumir("OperadorDecremento");
                Expressao();
                break;
            case "SimboloVirgula":
                Consumir("SimboloVirgula");
                Expressao();
                break;
            case "SimboloPontoVirgula":
                Consumir("SimboloPontoVirgula");
                //Expressao();
                break;
            case "SimboloFechaChaves":
                break;
            case "MacroInclude":
                Consumir("MacroInclude");
                Expressao();
                break;
            case "MacroDefine":
                Consumir("MacroDefine");
                Expressao();
                break;
            default:
                Erro("Erro de Sinal!");
                break;
        }
    }

    private void CondicaoIf() {
        String tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "PalavraReservadaIf":
                Consumir("PalavraReservadaIf");
                Consumir("SimboloAbreParenteses");
                Expressao();
                Consumir("SimboloFechaParenteses");
                break;
            case "PalavraReservadaElse":
                Consumir("PalavraReservadaElse");
                break;
            default:
                Erro("Erro Função If!");
                break;
        }

        tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "SimboloAbreChaves":
                Chaves();
                break;
            default:
                Codigo();
        }
    }

    private void LacoFor() {

        String tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "PalavraReservadaFor":
                Consumir("PalavraReservadaFor");
                Consumir("SimboloAbreParenteses");
                Expressao();
                Expressao();
                Expressao();
                Consumir("SimboloFechaParenteses");
                break;
            default:
                Erro("Erro Função For!");
                break;
        }

        tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "SimboloAbreChaves":
                Chaves();
                break;
            default:
                Codigo();
        }
    }

    private void LacoWhile() {
        String tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "PalavraReservadaDo":
                Consumir("PalavraReservadaWhile");
                Consumir("SimboloAbreParenteses");
                Expressao();
                Consumir("SimboloFechaParenteses");
                break;
            default:
                Erro("Erro Função While!");
                break;
        }
        tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "SimboloAbreChaves":
                Chaves();
                break;
            default:
                Codigo();
        }
    }

    private void LacoDo() {
        String tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "PalavraReservadaDo":
                Consumir("PalavraReservadaDo");
                break;
            default:
                Erro("Erro Função Do!");
                break;
        }

        tokenAtual = ObterTokenAtual();
        switch (tokenAtual) {
            case "SimboloAbreChaves":
                Chaves();
                break;
            default:
                Codigo();
        }

        Consumir("PalavraReservadaWhile");
        Consumir("SimboloAbreParenteses");
        Expressao();
        Consumir("SimboloFechaParenteses");
        Consumir("SimboloPontoVirgula");
    }

    boolean Analisar(ArrayList<String> tokens) {
        _lstTokens = (ArrayList<String>) tokens.clone();
        _LstAnalise = new ArrayList<String>();

        index = 0;

        Principal();

        return controle;
    }

    public ArrayList<String> getLstAnalise() {
        return _LstAnalise;
    }
}
